//------------------------------------------------------------------------------
// <copyright file="AutoCompleteControl.xaml.cs" company="Damian Antonowicz">
//       copyright © 2010 Damian Antonowicz
// </copyright>
// <author>Damian Antonowicz</author>
// <email>poczta@damianantonowicz.pl</email>
//------------------------------------------------------------------------------

using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using DotBeer.Business.Entities;
using DAnton.Utilities.Extensions;
using DAnton.Utilities.Helpers;
using System;
using System.Diagnostics;
using System.Collections;
using System.Reflection;

namespace DotBeer.UI.WPFClient
{
    /// <summary>
    /// Interaction logic for AutoCompleteControl.xaml
    /// </summary>
    public partial class AutoCompleteControl : UserControl
    {
        #region private members

        int selectedIndex = -1;
        bool userIsSelectingItem = false;

        #endregion

        #region properties
        
        public static readonly DependencyProperty TargetControlProperty =
            DependencyProperty.Register("TargetControl",
                                        typeof(TextBox),
                                        typeof(AutoCompleteControl),
                                        new PropertyMetadata(targetControl_Changed));

        public TextBox TargetControl
        {
            get { return (TextBox)this.GetValue(TargetControlProperty); }
            set { this.SetValue(TargetControlProperty, value); }
        }

        public static readonly DependencyProperty IsPopupOpenProperty =
            DependencyProperty.Register("IsPopupOpen",
                                        typeof(bool),
                                        typeof(AutoCompleteControl),
                                        new PropertyMetadata(false,
                                                             isPopupOpen_Changed));

        public bool IsPopupOpen
        {
            get { return (bool)this.GetValue(IsPopupOpenProperty); }
            set { this.SetValue(IsPopupOpenProperty, value); }
        }

        public static readonly DependencyProperty ItemsProperty =
            DependencyProperty.Register("Items",
                                        typeof(IList<AutoCompleteEntry>),
                                        typeof(AutoCompleteControl));

        public IEnumerable<AutoCompleteEntry> Items
        {
            get { return (IList<AutoCompleteEntry>)this.GetValue(ItemsProperty); }
            set { this.SetValue(ItemsProperty, value); }
        }

        public static readonly DependencyProperty MinimumProvidedCharactersProperty =
            DependencyProperty.Register("MinimumProvidedCharacters",
                                        typeof(int),
                                        typeof(AutoCompleteControl));

        public int MinimumProvidedCharacters
        {
            get { return (int)this.GetValue(MinimumProvidedCharactersProperty); }
            set { this.SetValue(MinimumProvidedCharactersProperty, value); }
        }

        #endregion

        #region constructors

        public AutoCompleteControl()
        {
            InitializeComponent();
        }

        #endregion

        #region private methods

        private static void targetControl_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != e.OldValue)
            {
                AutoCompleteControl autoComp = d as AutoCompleteControl;
                TextBox oldTextBox = e.OldValue as TextBox;
                TextBox newTextBox = e.NewValue as TextBox;

                if (oldTextBox != null)
                {
                    oldTextBox.LostFocus -= autoComp.targetControl_LostFocus;
                    oldTextBox.KeyUp -= autoComp.targetControl_KeyUp;
                    oldTextBox.GotFocus -= autoComp.targetControl_GotFocus;
                    oldTextBox.PreviewKeyDown -= autoComp.targetControl_PreviewKeyDown;
                    oldTextBox.TextChanged -= autoComp.targetControl_TextChanged;
                }

                if (newTextBox != null)
                {
                    autoComp.popup.PlacementTarget = newTextBox;

                    newTextBox.LostFocus += new RoutedEventHandler(autoComp.targetControl_LostFocus);
                    newTextBox.GotFocus += new RoutedEventHandler(autoComp.targetControl_GotFocus);
                    newTextBox.KeyUp += new KeyEventHandler(autoComp.targetControl_KeyUp);
                    newTextBox.PreviewKeyDown += new KeyEventHandler(autoComp.targetControl_PreviewKeyDown);
                    newTextBox.TextChanged += new TextChangedEventHandler(autoComp.targetControl_TextChanged);
                }
            }
        }

        private static void isPopupOpen_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (!(bool)e.NewValue)
            {
                AutoCompleteControl autoCompleteControl = d as AutoCompleteControl;
                autoCompleteControl.popup.IsOpen = false;
            }
        }

        private void targetControl_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (!this.userIsSelectingItem)
                this.SuggestList();
        }

        private void targetControl_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Tab || e.Key == Key.Escape)
            {
                this.popup.IsOpen = false;
                e.Handled = true;
            }

            if (e.Key == Key.Up && this.selectedIndex > 0)
            {
                this.userIsSelectingItem = true;
                this.listBox.SelectedIndex = --this.selectedIndex;
                this.listBox.ScrollIntoView(this.listBox.SelectedItem);
                this.TargetControl.SelectionStart = this.TargetControl.Text.Length;
            }

            if (e.Key == Key.Down && this.selectedIndex < this.listBox.Items.Count - 1)
            {
                this.userIsSelectingItem = true;
                this.listBox.SelectedIndex = ++this.selectedIndex;
                this.listBox.ScrollIntoView(this.listBox.SelectedItem);
                this.TargetControl.SelectionStart = this.TargetControl.Text.Length;
            }
        }

        private void targetControl_KeyUp(object sender, KeyEventArgs e)
        {
            this.userIsSelectingItem = false;
        }

        private void targetControl_LostFocus(object sender, RoutedEventArgs e)
        {
            this.popup.IsOpen = false;
        }

        private void targetControl_GotFocus(object sender, RoutedEventArgs e)
        {
            this.SuggestList();
        }

        private void SuggestList()
        {
            string text = TargetControl.Text;

            if (text.Length >= this.MinimumProvidedCharacters)
            {
                if (this.Items != null)
                {
                    this.listBox.ItemsSource = this.Items.Where(s => s.Name.ToUpper().Contains(text.ToUpper()))
                                                         .Select(s => s);

                    if (this.listBox.Items.Count > 0)
                    {
                        this.popup.IsOpen = true;
                        this.TargetControl.Text = text;
                        this.TargetControl.SelectionStart = this.TargetControl.Text.Length;

                        if (this.listBox.Items.Count > 0)
                            this.listBox.ScrollIntoView(this.listBox.Items[0]);

                        this.selectedIndex = -1;
                    }
                }
            }
            else
                this.popup.IsOpen = false;
        }

        #endregion
    }
}
